package io.github.yotta.logger.core.support;


import io.github.yotta.logger.anno.annotation.LogModel;
import io.github.yotta.logger.anno.annotation.LogOperation;
import io.github.yotta.logger.core.LogProperties;
import io.github.yotta.logger.core.model.LogAnnoMetaData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author yotta
 * @date 2023/3/22 9:05
 * 代理实现，代理所有的LogMetaDataPicker实现
 */
public class DefaultLogMetaDataDiscover implements LogMetaDataDiscover {

    private final static ConcurrentHashMap<Method, LogAnnoMetaData> LOG_META_DATA_MAP = new ConcurrentHashMap<>();


    private final LogProperties logProperties;

    public DefaultLogMetaDataDiscover(LogProperties logProperties) {
        this.logProperties = logProperties;
    }

    @Override
    public LogAnnoMetaData discover(Method method, Class<?> targetClass) {
        final LogAnnoMetaData logAnnoMetaDataCache = LOG_META_DATA_MAP.get(method);
        if (Objects.nonNull(logAnnoMetaDataCache)) {
            return logAnnoMetaDataCache;
        }
        LogOperation logOperationAnno = AnnotationUtils.findAnnotation(method, LogOperation.class);
        LogModel logModelAnno = AnnotationUtils.findAnnotation(targetClass, LogModel.class);
        ApiOperation apiOperationAnno = AnnotationUtils.findAnnotation(method, ApiOperation.class);
        Api apiAnno = AnnotationUtils.findAnnotation(targetClass, Api.class);
        String name = pickName(Objects.requireNonNull(logOperationAnno), apiOperationAnno);
        String model = pickModel(logModelAnno, logOperationAnno, apiAnno);
        final LogAnnoMetaData logAnnoMetaData = new LogAnnoMetaData(
                logProperties.getApplication(),
                name,
                model,
                logOperationAnno.bizIdFrom(),
                logOperationAnno.bizIdPath(),
                logOperationAnno.logError(),
                logOperationAnno.logParam());
        LOG_META_DATA_MAP.put(method, logAnnoMetaData);
        return logAnnoMetaData;
    }


    private String pickModel(LogModel logModelAnno, LogOperation logOperationAnno, Api apiAnno) {
        // 优先取LogOperation 再次取LogModel 最后取swagger
        if (StringUtils.isNotEmpty(logOperationAnno.model())) {
            return logOperationAnno.model();
        } else if (Objects.nonNull(logModelAnno) && StringUtils.isNotEmpty(logModelAnno.value())) {
            return logModelAnno.value();
        } else {
            return fromSwagger(apiAnno);
        }
    }

    private String fromSwagger(Api api) {
        if (Objects.nonNull(api)) {
            if (StringUtils.isNotEmpty(api.value())) {
                return api.value();
            }
            if (!ArrayUtils.isEmpty(api.tags())) {
                if (api.tags().length == 1) {
                    return api.tags()[0];
                }
                return ArrayUtils.toString(api.tags());
            }
        }
        return "";
    }

    private String pickName(LogOperation logOperationAnno, ApiOperation apiOperationAnno) {
        // 优先取LogOperation  后取swagger
        if (StringUtils.isNotEmpty(logOperationAnno.value())) {
            return logOperationAnno.value();
        } else {
            return apiOperationAnno.value();
        }
    }

}
